﻿#include "Graphics.h"
#include <sstream>
#include <d3dcompiler.h>
#include "MyUtils.h"

#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"D3DCompiler.lib")

Graphics::Graphics(HWND hWnd)
{
	DXGI_SWAP_CHAIN_DESC sd = {};
	sd.BufferDesc.Width = 0;  // 分辨率宽度
	sd.BufferDesc.Height = 0; // 分辨率高度
	sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;  // 缓冲区数据格式
	sd.BufferDesc.RefreshRate.Numerator = 0;
	sd.BufferDesc.RefreshRate.Denominator = 0;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount = 1;
	sd.OutputWindow = hWnd;
	sd.Windowed = TRUE;
	sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;//  DXGI_SWAP_EFFECT_DISCARD;
	sd.Flags = 0;

	UINT swapCreateFlags = 0u;
#ifndef NDEBUG
	swapCreateFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	// 创建device 和 swapchain
	// 可以得到 device swapchain 和 context
#ifndef NDEBUG
	m_DebugInfoManager.Set();
#endif // !NDEBUG

	MY_CHECK_HRESULT(D3D11CreateDeviceAndSwapChain(
		nullptr,
		D3D_DRIVER_TYPE_HARDWARE,
		nullptr,
		swapCreateFlags,
		nullptr,
		0,
		D3D11_SDK_VERSION,
		&sd,
		&m_SwapChain,
		&m_Device,
		nullptr,
		&m_Context
	));

	// 获取backbuffer
	ComPtr<ID3D11Resource> backBuffer;
	MY_CHECK_HRESULT(m_SwapChain->GetBuffer(0, __uuidof(ID3D11Resource), &backBuffer));

	// 创建 renderTargetView
	MY_CHECK_HRESULT(m_Device->CreateRenderTargetView(backBuffer.Get(), nullptr, &m_Target));

	//  创建深度模板缓冲
	// create depth stensil state
	D3D11_DEPTH_STENCIL_DESC dsDesc = {};
	dsDesc.DepthEnable = TRUE;
	dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
	ComPtr<ID3D11DepthStencilState> depthStencilState;
	MY_CHECK_HRESULT(m_Device->CreateDepthStencilState(&dsDesc, &depthStencilState));
	m_Context->OMSetDepthStencilState(depthStencilState.Get(), 1u);

	// 创建深度模板纹理
	ComPtr<ID3D11Texture2D> depthStencilTexture2d;
	D3D11_TEXTURE2D_DESC descDepth = {};
	descDepth.Width = 800u;
	descDepth.Height = 600u;
	descDepth.MipLevels = 1u;
	descDepth.ArraySize = 1u;
	descDepth.Format = DXGI_FORMAT_D32_FLOAT;
	descDepth.SampleDesc.Count = 1u;
	descDepth.SampleDesc.Quality = 0u;
	descDepth.Usage = D3D11_USAGE_DEFAULT;
	descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	MY_CHECK_HRESULT(m_Device->CreateTexture2D(&descDepth, nullptr, &depthStencilTexture2d));

	// 创建深度模板视图
	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
	descDSV.Format = DXGI_FORMAT_D32_FLOAT;
	descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	descDSV.Texture2D.MipSlice = 0u;
	MY_CHECK_HRESULT(m_Device->CreateDepthStencilView(depthStencilTexture2d.Get(), &descDSV, &m_DSV));

	m_Context->OMSetRenderTargets(1u, m_Target.GetAddressOf(), m_DSV.Get());
}


void Graphics::ClearBuffer(float red, float green, float blue)
{
	const float color[] = { red,green,blue,1.0f };
	m_Context->ClearRenderTargetView(m_Target.Get(), color);
	m_Context->ClearDepthStencilView(m_DSV.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
}

void Graphics::EndFrame()
{
	MY_CHECK_HRESULT(m_SwapChain->Present(1u, 0u));
}

void Graphics::TestDrawTriangle()
{
	float vertices[] = {
		-0.5f,0,
		0.5f,0,
		0,0.5f
	};

	// stage:
	// 1. IA
	// 2. VS
	// 3. PS
	// 4. OM

	// 设置顶点属性 vertexBuffer
	ComPtr<ID3D11Buffer> vertexBuffer;
	D3D11_BUFFER_DESC bd = {};
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.CPUAccessFlags = 0u;
	bd.MiscFlags = 0u;
	bd.ByteWidth = sizeof(vertices);
	bd.StructureByteStride = sizeof(float) * 2;

	D3D11_SUBRESOURCE_DATA sd = {};
	sd.pSysMem = vertices;
	MY_CHECK_HRESULT(m_Device->CreateBuffer(&bd, &sd, &vertexBuffer));

	// Bind vertex buffer to pipeline
	const UINT stride = sizeof(float) * 2;
	const UINT offset = 0u;
	m_Context->IASetVertexBuffers(0u, 1u, vertexBuffer.GetAddressOf(), &stride, &offset);

	// 设置 indexBuffer
	const unsigned short indices[] = { 0,1,2 };
	D3D11_BUFFER_DESC ibd = {};
	ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	ibd.Usage = D3D11_USAGE_DEFAULT;
	ibd.CPUAccessFlags = 0u;
	ibd.MiscFlags = 0u;
	ibd.ByteWidth = sizeof(indices);
	ibd.StructureByteStride = sizeof(unsigned short);
	D3D11_SUBRESOURCE_DATA isd = {};
	isd.pSysMem = indices;
	ComPtr<ID3D11Buffer> indexBuffer;
	MY_CHECK_HRESULT(m_Device->CreateBuffer(&ibd, &isd, &indexBuffer));
	m_Context->IASetIndexBuffer(indexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0u);

	// create vertex shader
	ComPtr<ID3D11VertexShader> vertexShader;
	ComPtr<ID3D11PixelShader> pixelShader;
	ComPtr<ID3DBlob> blob;

	// 参数需要宽字符
	MY_CHECK_HRESULT(D3DReadFileToBlob(L"pixel_shader_1.cso", &blob));
	MY_CHECK_HRESULT(m_Device->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, &pixelShader));
	m_Context->PSSetShader(pixelShader.Get(), nullptr, 0u);

	// vs
	MY_CHECK_HRESULT(D3DReadFileToBlob(L"vertex_shader_1.cso", &blob));
	MY_CHECK_HRESULT(m_Device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, &vertexShader));
	m_Context->VSSetShader(vertexShader.Get(), nullptr, 0u);

	// layout
	ComPtr<ID3D11InputLayout> inputLayout;
	const D3D11_INPUT_ELEMENT_DESC ied[] = {
		{ "Position",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
	};
	MY_CHECK_HRESULT(m_Device->CreateInputLayout(ied, (UINT)std::size(ied), blob->GetBufferPointer(), blob->GetBufferSize(), &inputLayout));
	m_Context->IASetInputLayout(inputLayout.Get());

	m_Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	// 配置 viewport
	D3D11_VIEWPORT vp;
	vp.Width = 800;
	vp.Height = 600;
	vp.MinDepth = 0;
	vp.MaxDepth = 1;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	m_Context->RSSetViewports(1u, &vp);

	// draw
	m_Context->DrawIndexed(std::size(indices), 0u, 0u);
}